/*
    Project:        Home Power Control
    File:           HPCSensor.h
    Author:         christian@karunamusic.at
    Date:           01.2015
    Description:    Baseclass for all sensors.
 */

#ifndef HPCSENSOR_H
#define HPCSENSOR_H

#include <QObject>
#include <QMutex>
#include <QString>
#include <QDataStream>
#include "../Values/HPCSensorValue.h"

class HPCServer; // forward declaration

class HPCSensor : public QObject
{
    Q_OBJECT

public:
    friend class HPCServer;

    /**< Type of the sensor. */
    enum class TSensorType
    {
        undefined = 0,
        HPCButton,
        HPCLight,
        HPCAnemometer,
        HPCRainGauge,
        HPCWindVane,
        HPCHumidity22,
        HPCTemperature22,
        HPCBarometer
    };

    /** \brief Constructor.
     *
     * \param type type of the sensor.
     * \param name name of the sensor.
     * \param id database id of the sensor.
     * \param pin GPIO pin number.
     */
    explicit HPCSensor( TSensorType type, const QString& name, quint32 id, quint8 pin );
    /** \brief Destructor.
     */
    virtual ~HPCSensor();

    /** \brief Get the type of the sensor-class.
     *
     * \return SensorType Type of the sensor (from enum SensorType).
     */
    virtual TSensorType Type() const
        { return m_Type; }

    /** \brief Get the name of the sensor-class.
     *
     * \return the classname as string.
     */
    QString Name() const
        { return m_Name; }

    /** \brief Get database id.
     *
     * \return unsigned long
     */
    inline quint32 ID() const
        { return m_ID; }

    /** \brief Get GPIO pin number.
     *
     * \return unsigned int
     */
    inline quint8 Pin() const
        { return m_Pin; }

    /** \brief Get the measuring unit.
     *
     * \return the measuring unit as string.
     */
    QString MeasureUnit() const
        { return m_MeasureUnit; }

    /** \brief Set the measuring unit.
     *
     * \return the class.
     */
    HPCSensor& MeasureUnit( const QString& munit );

    /** \brief Get the value.
     *
     * \return the value.
     */
    inline const HPCValue& Value() const
        { return m_Value; }

    /** \brief Get class with content as printable string.
     *
     * \return string
     */
    virtual QString asString() const;

    /** \brief Add upper and lower alarm to the SensorValue with the given id.
     * Can be called more than once to add alarms.
     *
     * \param Min The min-value as string or empty string if unused.
     * \param Max The max-value as string or empty string if unused.
     */
    void addAlarm(QString& Min, QString& Max );

    friend QDataStream& operator<< ( QDataStream& os, const HPCSensor& s );
    friend QDataStream& operator>> ( QDataStream& is, QMap<QString,HPCSensor*>& smap );

signals:
    /** \brief Signal a changed values.
     *
     * \param sender pointer to the sender of the notification.
     * \param val HPCValue - changed value of the sensor.
     */
    void changed( HPCSensor* sender, HPCSensorValue& val );

    /** \brief Signal an alarm.
     *
     * \param sender pointer to the sender of the notification.
     * \param val alarmed value of the sensor.
     * \param gt if true alarm is raised because of val >= max, otherwise val <= min.
     * \param ndx index of the fired alarm-value in the Min/Max-vector of HPCSensorValue.
     */
    void alarmed( HPCSensor* sender, HPCSensorValue& val, bool gt, unsigned int ndx ) const;

public slots:
    /** \brief Slot to read the sensor.
     *  Has to be implemented in derived classes!
     */
    virtual void Measure();

    /** \brief Slot for the change-signal of the sensor-value.
     *
     * \param val changed value of the sensor.
     */
    void ValueChanged( HPCValue& val );
    /** \brief Slot for the alarm-signal of the sensor-value.
     *
     * \param val alarmed value of the sensor.
     * \param gt if true alarm is raised because of val >= max, otherwise val <= min.
     * \param ndx index of the fired alarm-value in the Min/Max-vector of HPCSensorValue.
     */
    void ValueAlarmed( HPCSensorValue& val, bool gt, unsigned int ndx );

protected:
    void setValue( HPCValue& val );

    TSensorType    m_Type;        /**< Sensortype */
    const QString  m_Name;        /**< Name of the sensor. */
    const quint32  m_ID;          /**< Database id. */
    const quint8   m_Pin;         /**< GPIO pin number. */
    QString        m_MeasureUnit; /**< The measuring unit of the sensor. */
    HPCSensorValue m_Value;       /**< the measured value of the sensor. */
};

QDataStream& operator<< ( QDataStream& os, const HPCSensor& s );

#endif // HPCSENSOR_H
